﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Linq;
using Microsoft.Phone.Controls;
using System.Collections.Generic;

namespace WenslyWuLib.Common.DynamicEffect
{
    public class AnimationProvider
    {
        #region AnimationLevel

        public static int GetAnimationLevel(DependencyObject obj)
        {
            return (int)obj.GetValue(AnimationLevelProperty);
        }

        public static void SetAnimationLevel(DependencyObject obj, int value)
        {
            obj.SetValue(AnimationLevelProperty, value);
        }


        public static readonly DependencyProperty AnimationLevelProperty =
            DependencyProperty.RegisterAttached("AnimationLevel", typeof(int),
            typeof(AnimationProvider), new PropertyMetadata(-1));

        #endregion

        #region IsAnimationContainer

        public static bool GetIsAnimationContainer(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsAnimationContainerProperty);
        }

        public static void SetIsAnimationContainer(DependencyObject obj, bool value)
        {
            obj.SetValue(IsAnimationContainerProperty, value);
        }

        public static readonly DependencyProperty IsAnimationContainerProperty =
            DependencyProperty.RegisterAttached("IsAnimationContainer", typeof(bool),
            typeof(AnimationProvider), new PropertyMetadata(false));

        #endregion

        #region IsPivotAnimated

        //public static bool GetIsPivotAnimated(DependencyObject obj)
        //{
        //    return (bool)obj.GetValue(IsPivotAnimatedProperty);
        //}

        //public static void SetIsPivotAnimated(DependencyObject obj, bool value)
        //{
        //    obj.SetValue(IsPivotAnimatedProperty, value);
        //}

        //public static readonly DependencyProperty IsPivotAnimatedProperty =
        //    DependencyProperty.RegisterAttached("IsPivotAnimated", typeof(bool),
        //    typeof(ListAnimation), new PropertyMetadata(false, OnIsPivotAnimatedChanged));

        //private static void OnIsPivotAnimatedChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        //{
        //    ItemsControl list = d as ItemsControl;

        //    list.Loaded += (s2, e2) =>
        //    {

        //        //ListBoxAnimation(list as ListBox);
        //        return;
        //        // locate the pivot control that this list is within
        //        ListBox pivot = list as ListBox;//list.Ancestors<ListView>().Single() as ListView;

        //        // and its index within the pivot
        //        //int pivotIndex = pivot.Items.IndexOf(list.Ancestors<ListViewItem>().Single());
        //        int pivotIndex = 0;
        //        //bool selectionChanged = false;
        //        bool selectionChanged = true;
        //        pivot.SelectionChanged += (s3, e3) =>
        //        {
        //            selectionChanged = true;
        //        };

        //        // handle manipulation events which occur when the user
        //        // moves between pivot items
        //        //pivot.ManipulationCompleted += (s, e) =>
        //        //pivot.Loaded += (s, e) =>
        //        //  {
        //        //      if (!selectionChanged)
        //        //          return;

        //        //      selectionChanged = false;

        //        //      if (pivotIndex != pivot.SelectedIndex)
        //        //          return;

        //        // determine which direction this tab will be scrolling in from
        //        bool fromRight = true;//e.TotalManipulation.Translation.X <= 0;

        //        // locate the stack panel that hosts the items
        //        VirtualizingStackPanel vsp = list.Descendants<VirtualizingStackPanel>().First() as VirtualizingStackPanel;

        //        // iterate over each of the items in view
        //        int firstVisibleItem = (int)vsp.VerticalOffset;
        //        int visibleItemCount = (int)vsp.ViewportHeight;
        //        //for (int index = firstVisibleItem; index <= firstVisibleItem + visibleItemCount; index++)
        //        for (int index = 0; index < list.Items.Count; index++)
        //        {
        //            // find all the item that have the AnimationLevel attached property set
        //            var lbi = list.ItemContainerGenerator.ContainerFromIndex(index);
        //            if (lbi == null)
        //                continue;

        //            vsp.Dispatcher.BeginInvoke(
        //                new Action(() =>
        //                {
        //                    var animationTargets = lbi.Descendants().Where(p => ListAnimation.GetAnimationLevel(p) > -1);
        //                    foreach (FrameworkElement target in animationTargets)
        //                    {
        //                        // trigger the required animation
        //                        GetAnimation(target, fromRight).Begin();
        //                    }
        //                })
        //                , null);
        //        };
        //    };
        //}


        #endregion

        #region ListAnimation
        public static void ListBoxAnimation(ItemsControl list, PhoneApplicationPage page)
        {
            LeftToRightAnimation(list, page);
            //BottomToTopAnimation(list, page);
        }

        public static void LeftToRightAnimation(ItemsControl list, PhoneApplicationPage page)
        {
            ItemControlAnimation(list, 0 - (list.ActualWidth / 3), 0, TranslateTransform.XProperty, page);
        }

        public static void RightToLeftAnimation(ItemsControl list, PhoneApplicationPage page)
        {
            ItemControlAnimation(list,80, 0, TranslateTransform.XProperty, page);
        }

        public static void TopToBottomAnimation(ItemsControl list, PhoneApplicationPage page)
        {
            ItemControlAnimation(list, -100, 0, TranslateTransform.YProperty, page);
        }

        public static void BottomToTopAnimation(ItemsControl list, PhoneApplicationPage page)
        {
            ItemControlAnimation(list, 100, 0, TranslateTransform.YProperty, page);
        }

        private static void ItemControlAnimation(ItemsControl list, double offsetFrom, double offsetTo, object property, PhoneApplicationPage page)
        {
            List<ListBoxItem> stack = Common.FindAllChildOfType<ListBoxItem>(list);
            stack.Reverse(0, stack.Count);
            int index = 0;
            System.Diagnostics.Debug.WriteLine("list" + list.Items.Count()+stack.Count());
            foreach(var lbi in stack)
            {
                page.Dispatcher.BeginInvoke(
                    new Func<int,ListBoxItem, bool>((level,lbiObj) =>
                    {                       
                        var animationTargets = lbiObj.Descendants().Where(p => AnimationProvider.GetIsAnimationContainer(p));
                        foreach (FrameworkElement target in animationTargets)
                        {
                            GetAnimation(target, offsetFrom, 0, level, new PropertyPath("X")).Begin();                            
                        }                    
                        return true;
                    }), index++,lbi);
            }
        }

        /// <summary>
        /// Fade out  object
        /// </summary>
        /// <param name="element"></param>
        public static void FadeOutObject(FrameworkElement element,Action<Object> onFadaOutComplete,object item)
        {
            if (element == null)
            {
                if (onFadaOutComplete != null)
                    onFadaOutComplete(item);
            }

            double originalHeight = element.ActualHeight;
            element.Opacity = 0.0;
            Storyboard sb = GetSimpleAnimation(element.ActualHeight, 0, 0.3, new PropertyPath("Height"));
            Storyboard.SetTarget(sb, element);
            sb.Completed += new EventHandler(new Action<object, EventArgs>((o, e) =>
            {
                //reset last item X position
                ItemsControl list = element as ItemsControl;
                List<ListBoxItem> stack = Common.FindAllChildOfType<ListBoxItem>(list);
                stack.Reverse(0, stack.Count);
                foreach (var lbi in stack)
                {
                    var animationTargets = lbi.Descendants().Where(p => AnimationProvider.GetIsAnimationContainer(p));
                    foreach (FrameworkElement target in animationTargets)
                    {
                        target.RenderTransform.SetValue(TranslateTransform.XProperty, 80.0);
                    }
                }

                element.Height = originalHeight;
                element.Visibility = Visibility.Collapsed;
                element.Opacity = 1.0;
                if (onFadaOutComplete != null)
                    onFadaOutComplete(item);
            }));
            sb.Begin(); 
        }
        #endregion

        #region  GetAnimation

        public static Storyboard GetAnimation(FrameworkElement element, double fromValue, double toValue, double level, PropertyPath path)
        {
            TranslateTransform trans = new TranslateTransform() { X = fromValue };
            element.RenderTransform = trans;
            return GetAnimation(element, fromValue, toValue, level,path,trans);
        }

        /// <summary>
        /// Creates a TranslateTransform and associates it with the given element, returning
        /// a Storyboard which will animate the TranslateTransform with a SineEase function
        /// </summary>
        public static Storyboard GetAnimation(FrameworkElement element, double fromValue, double toValue, double level, PropertyPath path, DependencyObject trans)
        {
            Storyboard sb;
            double delay = level * 0.03 + 0.00;

            sb = new Storyboard();
            sb.BeginTime = TimeSpan.FromSeconds(delay);

            DoubleAnimation db = new DoubleAnimation();
            db.To = toValue;
            db.From = fromValue;
            db.EasingFunction = new SineEase();
            sb.Duration = db.Duration = TimeSpan.FromSeconds(0.4);
            sb.Children.Add(db);
            Storyboard.SetTarget(db, trans);
            Storyboard.SetTargetProperty(db, path);

            return sb;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fromValue"></param>
        /// <param name="toValue"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static Storyboard GetSimpleAnimation(double fromValue, double toValue,double duration, PropertyPath path)
        {
            Storyboard sb = new Storyboard();
            DoubleAnimation da = new DoubleAnimation();
            da.To = toValue;
            da.From = fromValue;
            da.EasingFunction = new QuinticEase(); //new SineEase();
            sb.Duration = da.Duration = TimeSpan.FromSeconds(duration);
            sb.Children.Add(da);
            sb.AutoReverse = false;
            Storyboard.SetTargetProperty(da, path);
            return sb;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fromValue"></param>
        /// <param name="toValue"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static Storyboard GetSimpleAnimation(double fromValue, double toValue, double duration, DependencyObject trans)
        {
            Storyboard sb = new Storyboard();
            DoubleAnimation da = new DoubleAnimation();
            da.To = toValue;
            da.From = fromValue;
            da.EasingFunction = new SineEase();
            sb.Duration = da.Duration = TimeSpan.FromSeconds(duration);
            sb.Children.Add(da);
            sb.AutoReverse = false;            
            Storyboard.SetTarget(da, trans);
            return sb;
        }
        #endregion
    }
}
